package com.heima.search.service;

import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.threadlocal.UserThreadLocalUtils;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.search.dtos.UserSearchDto;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class UserSearchService {

    @Autowired
    private RestHighLevelClient client;
    /**
     * 写入Es中，批量处理
     * @param articleDtoList
     */
    public void createIndexBatch(List<ArticleDto> articleDtoList) {
//      批量处理对象
        BulkRequest bulkRequest = new BulkRequest();

        for (ArticleDto articleDto : articleDtoList) {
            Map<String,Object> map = new HashMap<>();
            map.put("id",articleDto.getId());
            map.put("publishTime",articleDto.getPublishTime());
            map.put("layout",articleDto.getLayout());
            map.put("images",articleDto.getImages());
            map.put("staticUrl",articleDto.getStaticUrl());
            map.put("authorId",articleDto.getAuthorId());
            map.put("authorName",articleDto.getAuthorName());
            map.put("title",articleDto.getTitle());
            map.put("content",articleDto.getContent());
//            构造单条文档的创建对象
            IndexRequest indexRequest = new IndexRequest("app_info_article").
                    id(articleDto.getId().toString()).
                    source(JsonUtils.toString(map), XContentType.JSON);

            bulkRequest.add(indexRequest);
        }

//        把批量处理对象传输给Es
        try {
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("创建Es的索引失败");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }

    }

    @Autowired
    private RedisService redisService;
    /**
     * 用户关键词查询
     * @param dto
     * @return
     */
    public List<ArticleDto> search(UserSearchDto dto) {
//      用户输入的关键词
        String searchWords = dto.getSearchWords();
//        创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("app_info_article");

//        创建搜索条件构建器
        SearchSourceBuilder builder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        根据关键词查询,查询2个字段，是OR的关系
        boolQueryBuilder.must(
                QueryBuilders.
                        queryStringQuery(searchWords).
                        field("title").
                        field("content").
                        defaultOperator(Operator.OR)
        );
        if(dto.getMinBehotTime() != null){
            boolQueryBuilder.filter(
                    QueryBuilders.
                            rangeQuery("publishTime").
                            lt(dto.getMinBehotTime()));
        }
//        设置搜索条件
        builder.query(boolQueryBuilder);
//        排序
        builder.sort("publishTime", SortOrder.DESC);
//        分页
        builder.from(dto.getFromIndex());
        builder.size(dto.getPageSize());

//        增加高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        设置高亮条件
        highlightBuilder.preTags("<span>");
        highlightBuilder.field("title");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);


        searchRequest.source(builder);
        List<ArticleDto> list = new ArrayList<>();
//        搜索
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                String jsonStr = hit.getSourceAsString();
                ArticleDto articleDto = JsonUtils.toBean(jsonStr, ArticleDto.class);


                String title = hit.getHighlightFields().get("title").getFragments()[0].toString();
                articleDto.setTitle(title);


                list.add(articleDto);
            }
        } catch (IOException e) {
            log.error("Es搜索异常！");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }


        if(!CollectionUtils.isEmpty(list)) {
//        如果有搜索结果，把搜索的关键词放入redis
            Integer userId = UserThreadLocalUtils.getUserId();
            redisService.saveWords(searchWords, userId, dto.getEquipmentId());
        }

        return list;
    }
}
